package cn.daniel.framework.core.utils;

import org.apache.commons.lang3.StringUtils;

import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author daniel.tuen
 * @date 2025/9/1 17:06
 * @description 获取客户端请求Ip 地址
 */
public class IpUtil {

    /**
     * IPv4正则表达式
     */
    private static final String IPV4_PATTERN =
            "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";

    /**
     *
     * IPv6正则表达式
     */
    private static final String IPV6_PATTERN =
            // 1:2:3:4:5:6:7:8
            "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|" +
                    // 1::  1:2:3:4:5:6:7::
                    "([0-9a-fA-F]{1,4}:){1,7}:|" +
                    // 1::8  1:2:3:4:5:6::8  1:2:3:4:5:6::8
                    "([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" +
                    "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" +
                    "([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" +
                    "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" +
                    "([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" +
                    "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" +
                    // ::2:3:4:5:6:7:8  ::2:3:4:5:6:7:8 ::8       ::
                    ":((:[0-9a-fA-F]{1,4}){1,7}|:)|" +
                    // 链路本地地址
                    "fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" +
                    // IPv4映射地址
                    "::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|" +
                    "([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$";

    private static final Pattern ipv4Pattern = Pattern.compile(IPV4_PATTERN);
    private static final Pattern ipv6Pattern = Pattern.compile(IPV6_PATTERN);

    /**
     * 验证是否为有效的IPv4地址
     * @param ipAddress 待验证的IP地址
     * @return 如果是有效的IPv4地址则返回true，否则返回false
     */
    public static boolean isValidIPv4(String ipAddress) {
        if (ipAddress == null) {
            return false;
        }
        Matcher matcher = ipv4Pattern.matcher(ipAddress);
        return matcher.matches();
    }

    /**
     * 验证是否为有效的IPv6地址
     * @param ipAddress 待验证的IP地址
     * @return 如果是有效的IPv6地址则返回true，否则返回false
     */
    public static boolean isValidIPv6(String ipAddress) {
        if (ipAddress == null) {
            return false;
        }
        Matcher matcher = ipv6Pattern.matcher(ipAddress);
        return matcher.matches();
    }

    /**
     * 验证是否为有效的IP地址（IPv4或IPv6）
     * @param ipAddress 待验证的IP地址
     * @return 如果是有效的IP地址则返回true，否则返回false
     */
    public static boolean isValidIP(String ipAddress) {
        return isValidIPv4(ipAddress) || isValidIPv6(ipAddress);
    }

    /**
     * 检查IP地址是否在黑名单中（支持通配符*）
     * @param list 黑名单集合，支持精确匹配和通配符匹配
     * @param ipAddress 待检查的IP地址
     * @return 如果匹配黑名单规则则返回true，否则返回false
     */
    public static boolean inBlackList(Set<String> list, String ipAddress) {
        // 边界条件处理
        if (list == null || list.isEmpty() || StringUtils.isBlank(ipAddress)) {
            return false;
        }

        for (String pattern : list) {
            // 跳过空的黑名单规则
            if (StringUtils.isBlank(pattern)) {
                continue;
            }

            // 精确匹配
            if (!pattern.contains("*")) {
                if (pattern.equals(ipAddress)) {
                    return true;
                }
                continue;
            }

            // 通配符匹配处理
            if (matchesWildcardPattern(pattern, ipAddress)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查IP地址是否匹配带通配符的规则
     * 支持的模式：
     * - 前缀匹配：192.168.*
     * - 后缀匹配：*.168.1.1
     * - 中间匹配：192.*.1.1
     * - 多通配符：192.*.3.*（多个*会被视为单个处理）
     */
    private static boolean matchesWildcardPattern(String pattern, String ipAddress) {
        // 处理多个连续通配符的情况（如192.**.1 视为192.*.1）
        String normalizedPattern = pattern.replaceAll("\\*+", "*");

        int starIndex = normalizedPattern.indexOf('*');
        // 通配符不能是唯一字符（如 "*" 视为无效规则）
        if (starIndex == 0 && normalizedPattern.length() == 1) {
            return false;
        }

        String prefix = normalizedPattern.substring(0, starIndex);
        String suffix = normalizedPattern.substring(starIndex + 1);

        // 前缀+后缀组合匹配（如192.*.1）
        if (StringUtils.isNotBlank(prefix) && StringUtils.isNotBlank(suffix)) {
            return ipAddress.startsWith(prefix) && ipAddress.endsWith(suffix);
        }

        // 仅前缀匹配（如192.168.*）
        if (StringUtils.isNotBlank(prefix)) {
            return ipAddress.startsWith(prefix);
        }

        // 仅后缀匹配（如*.168.1.1）
        if (StringUtils.isNotBlank(suffix)) {
            return ipAddress.endsWith(suffix);
        }

        return false;
    }
}
